﻿
Public Class valueInterval

    Public Class interval
        Public upperBound As Double
        Public lowerBound As Double
        Public includeUpperBound As Boolean
        Public includeLowerBound As Boolean

        Public Function match(ByVal i As Double) As Boolean
            If includeLowerBound AndAlso includeUpperBound Then
                Return i <= upperBound AndAlso i >= lowerBound
            ElseIf includeLowerBound Then
                Return i < upperBound AndAlso i >= lowerBound
            ElseIf includeUpperBound Then
                Return i <= upperBound AndAlso i > lowerBound
            Else
                Return i < upperBound AndAlso i > lowerBound
            End If
        End Function
    End Class

    'leave these changeable, for some special requirement
    Public Shared separator1 As Char = character.minusSign
    Public Shared includeLowerBoundChar2 As Char = character.leftMidBracket
    Public Shared includeUpperBoundChar2 As Char = character.rightMidBracket
    Public Shared start2 As String = character.leftBracket + includeLowerBoundChar2
    Public Shared end2 As String = character.rightBracket + includeUpperBoundChar2
    Public Shared separator2 As Char = character.comma

    Public Shared Function match(ByVal s As String, ByVal interval As interval) As Boolean
        Dim i As Double
        If convertor.todouble(s, i) Then
            Return match(i, interval)
        Else
            Return False
        End If
    End Function

    Public Shared Function match(ByVal i As Double, ByVal interval As interval) As Boolean
        If interval Is Nothing Then
            Return False
        Else
            Return interval.match(i)
        End If
    End Function

    Public Shared Function match(ByVal s As String, ByVal interval As String) As Boolean
        Dim i As Double
        If convertor.todouble(s, i) Then
            Return match(i, interval)
        Else
            Return False
        End If
    End Function

    Public Shared Function match(ByVal i As Double, ByVal interval As String) As Boolean
        Dim intv As interval = Nothing
        If parseInterval(interval, intv) Then
            If intv Is Nothing Then
                debugassert(False, "intv is a nothing interval instance.")
                Return False
            Else
                Return match(i, intv)
            End If
        Else
            Return False
        End If
    End Function

    Public Shared Function parseInterval(ByVal s As String, ByRef interval As interval) As Boolean
        Return parseInterval1(s, interval) OrElse parseInterval2(s, interval)
    End Function

    'a-b mode, same as [a,b)
    Private Shared Function parseInterval1(ByVal s As String, ByRef interval As interval) As Boolean
        Dim index As Int64
        index = strindexof(s, separator1, False)
        If index <> npos Then
            If interval Is Nothing Then
                interval = New interval()
            End If
            interval.includeLowerBound = True
            interval.includeUpperBound = False
            If convertor.todouble(strleft(s, index), interval.lowerBound) AndAlso _
               convertor.todouble(strmid(s, index + 1), interval.upperBound) Then
                Return True
            Else
                Return False
            End If
        Else
            Return False
        End If
    End Function

    '[a,b] mode
    Private Shared Function parseInterval2(ByVal s As String, ByRef interval As interval) As Boolean
        Dim left As Char
        Dim right As Char
        left = strleft(s, 1)
        right = strright(s, 1)
        s = strmid(s, 1, strlen(s) - 2)
        If strindexof(start2, left, False) <> npos AndAlso _
            strindexof(end2, right, False) <> npos Then
            Dim index As Int64
            index = strindexof(s, separator2, False)
            If index <> npos Then
                If interval Is Nothing Then
                    interval = New interval()
                End If
                interval.includeLowerBound = (left = includeLowerBoundChar2)
                interval.includeUpperBound = (right = includeUpperBoundChar2)
                If convertor.todouble(strleft(s, index), interval.lowerBound) AndAlso _
                   convertor.todouble(strmid(s, index + strlen(separator2)), interval.upperBound) Then
                    Return True
                Else
                    Return False
                End If
            Else
                Return False
            End If
        Else
            Return False
        End If
    End Function

    Public Shared Sub performanceTest()
        Dim roundcount As Int64 = 102400
        If isreleasebuild() Then
            roundcount *= 20
        End If

        raiseError("******** valueInterval automatical perfTest ********")
        Dim i As Int64
        For i = 0 To roundcount - 1
            Dim l As Double
            Dim u As Double
            Dim s As Double
            l = rnd(0, 1024)
            u = rnd(0, 1024)
            s = rnd(0, 1024)

            Dim interval As String = Nothing
            If rnd(0, 1) < 0.5 Then
                'mode 1, a-b
                interval = Convert.ToString(l) + separator1 + Convert.ToString(u)
            Else
                'mode 2, [a,b]
                If rnd(0, 1) < 0.5 Then
                    '(
                    interval = character.leftBracket
                Else
                    '[
                    interval = character.leftMidBracket
                End If
                interval += Convert.ToString(l) + separator2 + Convert.ToString(u)
                If rnd(0, 1) < 0.5 Then
                    ')
                    interval += character.rightBracket
                Else
                    ']
                    interval += character.rightMidBracket
                End If
            End If
            If rnd(0, 1) < 0.5 Then
                'use s as string
                raiseError("interval check " + Convert.ToString(s) + " as string based on " + interval)
                match(Convert.ToString(s), interval)
            Else
                'use s as double
                raiseError("interval check " + Convert.ToString(s) + " as double based on " + interval)
                match(s, interval)
            End If
        Next
        raiseError("*********** finish valueInterval perfTest **********")
    End Sub
End Class
